/*
 * Copyright © OpenAtom Foundation.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package io.iec.edp.caf.databaseobject.manager.export;

import io.iec.edp.caf.databaseobject.IDatabaseObjectSQLReflect;
import io.iec.edp.caf.databaseobject.api.entity.*;
import io.iec.edp.caf.databaseobject.common.database.GspDatabase;
import io.iec.edp.caf.databaseobject.common.database.GspDbFactory;
import io.iec.edp.caf.databaseobject.common.helper.SQLReflectHelper;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataBuilder;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl;
import org.hibernate.resource.transaction.spi.DdlTransactionIsolator;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.tool.schema.extract.internal.ColumnInformationImpl;
import org.hibernate.tool.schema.extract.internal.TableInformationImpl;
import org.hibernate.tool.schema.extract.spi.*;
import org.hibernate.tool.schema.internal.Helper;
import org.hibernate.tool.schema.internal.HibernateSchemaManagementTool;
import org.hibernate.tool.schema.internal.exec.JdbcContext;
import org.hibernate.tool.schema.spi.SchemaManagementTool;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @author liu_wei
 */
public class DatabaseObjectExportManager {

    public DatabaseObjectExportManager(DBInfo info) {
        this.dbInfo = info;
        this.dbType = info.getDbType();
    }

    private StandardServiceRegistryBuilder serviceRegistryBuilder;
    private HibernateSchemaManagementTool tool;
    private Metadata metadata;
    private DBInfo dbInfo;
    private DbType dbType;

    private void applySetting() {
        serviceRegistryBuilder = new StandardServiceRegistryBuilder();
        serviceRegistryBuilder.applySetting("hibernate.show_sql", "false");
        serviceRegistryBuilder.applySetting("hibernate.format_sql", "true");
        serviceRegistryBuilder.applySetting("hibernate.use_sql_comments", "true");
        serviceRegistryBuilder.applySetting("schemaUpdate", "true");
        serviceRegistryBuilder.applySetting("hibernate.hbm2ddl.auto", "update");
        serviceRegistryBuilder.applySetting("spring.jpa.hibernate.ddl-auto", "update");
        serviceRegistryBuilder.applySetting("hibernate.connection.autocommit", "true");
        serviceRegistryBuilder.applySetting("hibernate.current_session_context_class", "thread");
        serviceRegistryBuilder.applySetting("hibernate.temp.use_jdbc_metadata_defaults", "false");
        serviceRegistryBuilder.applySetting("hibernate.connection.url", dbInfo.getUrl());
        serviceRegistryBuilder.applySetting("hibernate.connection.username", dbInfo.getUserName());
        serviceRegistryBuilder.applySetting("hibernate.connection.password", dbInfo.getPassWord());

        //修改为springboot启动后，必须加上default_schema，SqlServer下还需要default_catalog
        if (dbType == DbType.PgSQL) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "org.postgresql.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");
        } else if (dbType == DbType.SQLServer) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.default_catalog", "[" + dbInfo.getDbName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "com.microsoft.sqlserver.jdbc.SQLServerDriver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.SQLServer2012Dialect");
        } else if (dbType == DbType.Oracle) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName().toUpperCase() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "oracle.jdbc.OracleDriver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.Oracle12cDialect");
        } else if (dbType == DbType.DM) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName().toUpperCase() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "dm.jdbc.driver.DmDriver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.DmDialect");
        } else if (dbType == DbType.HighGo) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "com.highgo.jdbc.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.HgdbDialect");
        } else if (dbType == DbType.MySQL) {
            //serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getDbName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.default_catalog", "[" + dbInfo.getDbName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "com.mysql.cj.jdbc.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
        } else if (dbType == DbType.Oscar) {
            //serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getDbName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName().toUpperCase() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "com.oscar.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.OscarDialect");
        } else if (dbType == DbType.Kingbase) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "com.kingbase8.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.Kingbase8Dialect");
        } else if (dbType == DbType.DB2) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "com.ibm.db2.jcc.DB2Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.DB2Dialect");
        } else if (dbType == DbType.OpenGauss) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "org.opengauss.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");
        } else if (dbType == DbType.GBase8s) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "cn.gbase8s.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");
        } else if (dbType == DbType.GBase8c) {
            serviceRegistryBuilder.applySetting("hibernate.default_schema", "[" + dbInfo.getUserName() + "]");
            serviceRegistryBuilder.applySetting("hibernate.connection.driver_class", "cn.gbase8c.Driver");
            serviceRegistryBuilder.applySetting("hibernate.dialect", "org.hibernate.dialect.PostgreSQL95Dialect");
        }
    }

    /**
     * 通过hibernate获取表信息
     *
     * @return 表信息
     */
    private NameSpaceTablesInformation getTablesInfo() {
        try {
            applySetting();

            ServiceRegistry serviceRegistry = serviceRegistryBuilder.build();
            MetadataSources metadataSources = new MetadataSources(serviceRegistry);
            MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder();
            metadata = metadataBuilder.build();

            SchemaManagementTool smt = serviceRegistry.getService(SchemaManagementTool.class);
            if (smt == null || !HibernateSchemaManagementTool.class.isInstance(smt)) {
                smt = new HibernateSchemaManagementTool();
                ((HibernateSchemaManagementTool) smt).injectServices((ServiceRegistryImplementor) serviceRegistry);
            }
            this.tool = (HibernateSchemaManagementTool) smt;

            Field configurationValues = ((StandardServiceRegistryImpl) serviceRegistry).getClass().getDeclaredField("configurationValues");
            configurationValues.setAccessible(true);
            final JdbcContext jdbcContext = tool.resolveJdbcContext((Map) configurationValues.get(serviceRegistry));
            final DdlTransactionIsolator ddlTransactionIsolator = tool.getDdlTransactionIsolator(jdbcContext);

            final DatabaseInformation databaseInformation = Helper.buildDatabaseInformation(
                    tool.getServiceRegistry(),
                    ddlTransactionIsolator,
                    metadata.getDatabase().getDefaultNamespace().getName()
            );
            NameSpaceTablesInformation tableInfo = databaseInformation.getTablesInformation(metadata.getDatabase().getDefaultNamespace());
            return tableInfo;
        } catch (Exception e) {
            throw new RuntimeException("获取" + dbInfo.getUserName() + "数据库中所有表信息出错：" + e.getMessage(), e);
        }
    }

    /**
     * 根据表名和业务Id获取DBO列表
     *
     * @param tablesName       表名列表
     * @param businessObjectId 业务Id
     * @return DBO列表
     */
    public List<AbstractDatabaseObject> getDatabaseObjectsByTablesName(List<String> tablesName, String dboName, String businessObjectId) {
        NameSpaceTablesInformation tablesInformation = getTablesInfo();
        String currentTable = "";
        List<AbstractDatabaseObject> objects = new ArrayList<>();
        try {
            for (String table : tablesName) {
                if (dbType == DbType.Oracle || dbType == DbType.DM || dbType == DbType.Oscar || dbType == DbType.DB2) {
                    table = table.toUpperCase();
                }
                if (dbType == DbType.PgSQL || dbType == DbType.HighGo || dbType == DbType.MySQL || dbType==DbType.OpenGauss
                        || dbType == DbType.GBase8s || dbType == DbType.GBase8c) {
                    table = table.toLowerCase();
                }
                String currentDboName = StringUtils.isNotBlank(dboName) ? dboName : table;
                DatabaseObjectTable objectTable = new DatabaseObjectTable(table, currentDboName, false, false, false, false, businessObjectId);
                currentTable = table;

                TableInformation tableInfo = tablesInformation.getTableInformation(table);
                if (tableInfo == null) {
                    throw new RuntimeException("数据库中不存在表：" + table);
                }


                Field columns = ((TableInformationImpl) tableInfo).getClass().getDeclaredField("columns");
                columns.setAccessible(true);
                Map<Identifier, ColumnInformation> realColumns = (Map<Identifier, ColumnInformation>) columns.get(tableInfo);
                List<ColumnInformation> columnInformations = new ArrayList<>(realColumns.values());
                //列
                for (ColumnInformation columnInfo : columnInformations) {
                    String columnId = UUID.randomUUID().toString();
                    String columnCode = getColumnCode(columnInfo);
                    String columnName = columnCode;
                    DataType dataType = getColumnDataType(columnInfo);
                    int length = getLength(dataType, columnInfo);
                    int precision = 0;
                    int scale = 0;
                    if (dataType == DataType.Decimal) {
                        length = 0;
                        precision = columnInfo.getColumnSize();
                        scale = columnInfo.getDecimalDigits();
                    }
                    String defaultValue = getDefaultValue(dbInfo.getUserName(), table, columnCode);
                    boolean ifUnique = false;
                    boolean ifPK = false;
                    if(columnInfo.getContainingTableInformation().getPrimaryKey() != null){
                        ifPK = columnInfo.getContainingTableInformation().getPrimaryKey().getColumns().iterator().next().getColumnIdentifier().getText().equals(columnCode);
                    }
                    boolean isNullable = columnInfo.getNullable().toBoolean(true);
                    boolean isI18n = false;
                    objectTable.addColumn(columnId, columnCode, columnName, dataType, length, precision, scale, defaultValue, ifUnique, ifPK, isNullable, isI18n);
                }
                //索引
                Iterable<IndexInformation> indexInfos = columnInformations.get(0).getContainingTableInformation().getIndexes();
                objectTable.setIndexes(getDatabaseObjectIndex(objectTable, indexInfos));
                objects.add(objectTable);
            }
            return objects;
        } catch (Exception e) {
            throw new RuntimeException("根据表" + currentTable + "导出DBO出错：" + e.getMessage(), e);
        }
    }

    /**
     * 获取索引
     *
     * @param objectTable 现有DBO实体
     * @param indexInfos  数据库中索引信息
     * @return DBO中索引
     */
    private List<DatabaseObjectIndex> getDatabaseObjectIndex(DatabaseObjectTable objectTable, Iterable<IndexInformation> indexInfos) {
        List<DatabaseObjectIndex> indexes = new ArrayList<>();
        for (IndexInformation indexInformation : indexInfos) {
            boolean isPkeyIndex = false;
            List<DatabaseObjectColumn> columnList = new ArrayList<>();
            for (ColumnInformation columnInfo : indexInformation.getIndexedColumns()) {
                DatabaseObjectColumn databaseObjectColumn = objectTable.getColumnByCode(getColumnCode(columnInfo));
                //去除主键索引
                if (databaseObjectColumn.isIfPrimaryKey() && indexInformation.getIndexedColumns().size() == 1) {
                    isPkeyIndex = true;
                } else {
                    isPkeyIndex = false;
                }
                columnList.add(databaseObjectColumn);
            }
            if (isPkeyIndex) {
                continue;
            }
            DatabaseObjectIndex index = new DatabaseObjectIndex();
            index.setId(UUID.randomUUID().toString());
            index.setCode(indexInformation.getIndexIdentifier().getText());
            index.setName(indexInformation.getIndexIdentifier().getText());
            index.setColumns(columnList);
            indexes.add(index);
        }
        return indexes;
    }

    /**
     * 获取字段长度
     *
     * @param dataType   数据类型
     * @param columnInfo 字段信息
     * @return 字段长度
     */
    private int getLength(DataType dataType, ColumnInformation columnInfo) {
        if (dataType == DataType.DateTime || dataType == DataType.TimeStamp || dataType == DataType.Clob || dataType == DataType.NClob || dataType == DataType.Blob || dataType == DataType.SmallInt || dataType == DataType.Int) {
            return 0;
        } else {
            return columnInfo.getColumnSize();
        }
    }

    /**
     * 获取字段名称
     *
     * @param columnInfo 字段信息
     * @return 字段名称
     */
    private String getColumnCode(ColumnInformation columnInfo) {
        try {
            Field columnIdentifier = ((ColumnInformationImpl) columnInfo).getClass().getDeclaredField("columnIdentifier");
            columnIdentifier.setAccessible(true);
            Identifier identifier = (Identifier) columnIdentifier.get(columnInfo);
            return identifier.getText();
        } catch (Exception e) {
            throw new RuntimeException("获取字段名称报错：" + e.getMessage(), e);
        }
    }

    /**
     * 根据字段信息转化成DBO中支持的字段类型
     *
     * @param columnInfo 字段信息
     * @return DBO中支持的字段类型
     */
    private DataType getColumnDataType(ColumnInformation columnInfo) {
        if (dbType == DbType.PgSQL || dbType == DbType.HighGo || dbType == DbType.OpenGauss
                || dbType == DbType.GBase8s || dbType == DbType.GBase8c) {
            return getPgColumnDataType(columnInfo);
        } else if (dbType == DbType.SQLServer) {
            return getSqlServerColumnDataType(columnInfo);
        } else if (dbType == DbType.Oracle) {
            return getOracleColumnDataType(columnInfo);
        } else if (dbType == DbType.DM) {
            return getDMColumnDataType(columnInfo);
        } else if (dbType == DbType.MySQL) {
            return getMySqlColumnDataType(columnInfo);
        } else if (dbType == DbType.Oscar) {
            return getOracleColumnDataType(columnInfo);
        } else if (dbType == DbType.Kingbase) {
            return getOracleColumnDataType(columnInfo);
        } else if (dbType == DbType.DB2) {
            return getDB2ColumnDataType(columnInfo);
        } else {
            throw new RuntimeException("暂不支持的数据类型");
        }
    }

    /**
     * 获取表中列的默认值
     *
     * @param schemaName schema
     * @param tableName  表名
     * @param colName    列名
     * @return 默认值
     */
    private String getDefaultValue(String schemaName, String tableName, String colName) {
        IDatabaseObjectSQLReflect reflectManager = SQLReflectHelper.getInstance().GetManager(dbType.toString());
        String defaultSql = reflectManager.getDefaultValue(schemaName, tableName, colName);
        GspDatabase gspDatabase = GspDbFactory.getDatabase(dbInfo);
        ResultSet resultSet = null;
        String defaultValue = null;
        try {
            resultSet = gspDatabase.executeResultSet(defaultSql);
            if (resultSet != null) {
                while (resultSet.next()) {
                    defaultValue = resultSet.getString(1);
                }
            }
            //SqlServer中会出现((123))
            if (dbType == DbType.SQLServer && defaultValue != null && defaultValue.length() > 0 && defaultValue.startsWith("((") && defaultValue.endsWith("))")) {
                defaultValue = defaultValue.replace("((", "").replace("))", "");
            }
            //PG中默认值会出现“'1'::”
            if (defaultValue != null && defaultValue.length() > 0 && defaultValue.contains("'")) {
                defaultValue = defaultValue.substring(defaultValue.indexOf("'") + 1, defaultValue.lastIndexOf("'"));
            }
            if (("sysdate").equalsIgnoreCase(defaultValue)) {
                defaultValue = "getdate()";
            }
        } catch (Exception e) {
            throw new RuntimeException("获取表" + tableName + "中" + colName + "列默认值出错:", e);
        } finally {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            gspDatabase.close();
        }
        return defaultValue;
    }

    /**
     * 根据PG数据库中原生类型转化DBO中支持的字段类型
     *
     * @param columnInfo 数据库中原生类型
     * @return DBO中支持的字段类型
     */
    private DataType getPgColumnDataType(ColumnInformation columnInfo) {
        DataType type = null;
        switch (columnInfo.getTypeName().toLowerCase()) {
            case "char":
            case "bpchar":
                type = DataType.Char;
                break;
            case "varchar":
                type = DataType.Varchar;
                break;
            case "text":
                type = DataType.Clob;
                break;
            case "int4":
            case "int8":
                type = DataType.Int;
                break;
            case "numeric":
            case "decimal":
            case "money":
                type = DataType.Decimal;
                break;
            case "date":
                type = DataType.DateTime;
                break;
            case "timestamp":
                type = DataType.TimeStamp;
                break;
            case "bytea":
                type = DataType.Blob;
                break;
            case "bool":
                type = DataType.Boolean;
                break;
            case "int2":
                type = DataType.SmallInt;
                break;
            default:
                type = DataType.NotSupported;
                break;
        }
        return type;
    }

    /**
     * 根据Oracle数据库中原生类型转化DBO中支持的字段类型
     *
     * @param columnInfo 数据库中原生类型
     * @return DBO中支持的字段类型
     */
    private DataType getOracleColumnDataType(ColumnInformation columnInfo) {
        DataType type = null;
        switch (columnInfo.getTypeName().toLowerCase()) {
            case "char":
                type = DataType.Char;
                break;
            case "nchar":
                type = DataType.NChar;
                break;
            case "varchar":
            case "varchar2":
                type = DataType.Varchar;
                break;
            case "nvarchar2":
                type = DataType.NVarchar;
                break;
            case "clob":
            case "long":
                type = DataType.Clob;
                break;
            case "nclob":
                type = DataType.NClob;
                break;
            case "int":
            case "integer":
                type = DataType.Int;
                break;
            case "numeric":
            case "decimal":
            case "float":
                type = DataType.Decimal;
                break;
            case "date":
                type = DataType.DateTime;
                break;
            case "timestamp":
                type = DataType.TimeStamp;
                break;
            case "blob":
                type = DataType.Blob;
                break;
            case "number":
                if (columnInfo.getColumnSize() == 1) {
                    type = DataType.Boolean;
                    break;
                }
                if (columnInfo.getDecimalDigits() > 0) {
                    type = DataType.Decimal;
                    break;
                } else {
                    type = DataType.Int;
                    break;
                }
            case "smallint":
                type = DataType.SmallInt;
                break;
            default:
                type = DataType.NotSupported;
                break;
        }
        return type;
    }

    /**
     * 根据DB2数据库中原生类型转化DBO中支持的字段类型
     *
     * @param columnInfo 数据库中原生类型
     * @return DBO中支持的字段类型
     */
    private DataType getDB2ColumnDataType(ColumnInformation columnInfo) {
        DataType type = null;
        switch (columnInfo.getTypeName().toLowerCase()) {
            case "char":
            case "character":
                type = DataType.Char;
                break;
            case "varchar":
            case "long varchar":
                type = DataType.Varchar;
                break;
            case "clob":
            case "long":
                type = DataType.Clob;
                break;
            case "int":
            case "bigint":
            case "integer":
                type = DataType.Int;
                break;
            case "float":
                type = DataType.Float;
                break;
            case "numeric":
            case "decimal":
            case "num":
            case "real":
            case "double":
                type = DataType.Decimal;
                break;
            case "date":
                type = DataType.DateTime;
                break;
            case "time":
            case "timestamp":
                type = DataType.TimeStamp;
                break;
            case "blob":
                type = DataType.Blob;
                break;
            case "smallint":
                type = DataType.SmallInt;
                break;
            default:
                type = DataType.NotSupported;
                break;
        }
        return type;
    }

    /**
     * 根据SqlServer数据库中原生类型转化DBO中支持的字段类型
     *
     * @param columnInfo 数据库中原生类型
     * @return DBO中支持的字段类型
     */
    private DataType getSqlServerColumnDataType(ColumnInformation columnInfo) {
        DataType type = null;
        switch (columnInfo.getTypeName().toLowerCase()) {
            case "char":
                type = DataType.Char;
                break;
            case "nchar":
                type = DataType.NChar;
                break;
            case "varchar":
                type = DataType.Varchar;
                break;
            case "nvarchar":
                type = DataType.NVarchar;
                break;
            case "text":
                type = DataType.Clob;
                break;
            case "ntext":
                type = DataType.NClob;
                break;
            case "int":
            case "bigint":
                type = DataType.Int;
                break;
            case "numeric":
            case "decimal":
            case "float":
            case "money":
                type = DataType.Decimal;
                break;
            case "date":
                type = DataType.DateTime;
                break;
            case "datetime":
            case "datetime2":
            case "datetimeoffset":
            case "timestamp":
            case "time":
                type = DataType.TimeStamp;
                break;
            case "image":
                type = DataType.Blob;
                break;
            case "bit":
                if (columnInfo.getColumnSize() == 0) {
                    type = DataType.Boolean;
                    break;
                }
            case "smallint":
            case "tinyint":
                type = DataType.SmallInt;
                break;
            default:
                type = DataType.NotSupported;
                break;
        }
        return type;
    }

    /**
     * 根据DM数据库中原生类型转化DBO中支持的字段类型
     *
     * @param columnInfo 数据库中原生类型
     * @return DBO中支持的字段类型
     */
    private DataType getDMColumnDataType(ColumnInformation columnInfo) {
        DataType type = null;
        switch (columnInfo.getTypeName().toLowerCase()) {
            case "char":
            case "character":
                type = DataType.Char;
                break;
            case "nchar":
                type = DataType.NChar;
                break;
            case "nvarchar":
            case "nvarchar2":
                type = DataType.NVarchar;
                break;
            case "varchar":
            case "varchar2":
                type = DataType.Varchar;
                break;
            case "clob":
            case "text":
                type = DataType.Clob;
                break;
            case "nclob":
            case "ntext":
                type = DataType.NClob;
                break;
            case "int":
            case "integer":
            case "bigint":
                type = DataType.Int;
                break;
            case "numeric":
            case "decimal":
            case "float":
                type = DataType.Decimal;
                break;
            case "date":
                type = DataType.DateTime;
                break;
            case "timestamp":
                type = DataType.TimeStamp;
                break;
            case "blob":
            case "image":
                type = DataType.Blob;
                break;
            case "number":
                if (columnInfo.getDecimalDigits() > 0) {
                    type = DataType.Decimal;
                    break;
                }
            case "bit":
                if (columnInfo.getColumnSize() == 1) {
                    type = DataType.Boolean;
                    break;
                }
            case "smallint":
            case "tinyint":
                type = DataType.SmallInt;
                break;
            default:
                type = DataType.NotSupported;
                break;
        }
        return type;
    }

    /**
     * 根据MySql数据库中原生类型转化DBO中支持的字段类型
     *
     * @param columnInfo 数据库中原生类型
     * @return DBO中支持的字段类型
     */
    private DataType getMySqlColumnDataType(ColumnInformation columnInfo) {
        DataType type = null;
        switch (columnInfo.getTypeName().toLowerCase()) {
            case "char":
                type = DataType.Char;
                break;
            case "varchar":
                type = DataType.Varchar;
                break;
            case "longtext":
            case "text":
            case "tinytext":
                type = DataType.Clob;
                break;
            case "int":
            case "integer":
            case "bigint":
                type = DataType.Int;
                break;
            case "numeric":
            case "decimal":
            case "float":
                type = DataType.Decimal;
                break;
            case "date":
                type = DataType.DateTime;
                break;
            case "datetime":
            case "timestamp":
                type = DataType.TimeStamp;
                break;
            case "blob":
            case "longblob":
            case "tinyblob":
                type = DataType.Blob;
                break;
            case "bit":
            case "tinyint":
                if (columnInfo.getColumnSize() == 1) {
                    type = DataType.Boolean;
                    break;
                }
            case "smallint":
                type = DataType.SmallInt;
                break;
            default:
                type = DataType.NotSupported;
                break;
        }
        return type;
    }
}
